백준 10830번

행렬 제곱

Posted by ChoiCube84 on September 12, 2023 · 10 mins read

백준 10830번

오늘 풀어본 문제는 백준의 10830번 문제1이다. 문제 풀이에 사용한 언어는 C++ 이다.

solved.ac 기준 CLASS

CLASS 4

문제 정보

이 문제의 내용과 조건은 다음과 같다.

문제

크기가 $N*N$ 인 행렬 $A$ 가 주어진다. 이때, $A$ 의 $B$ 제곱을 구하는 프로그램을 작성하시오. 수가 매우 커질 수 있으니, $A^B$ 의 각 원소를 $1,000$ 으로 나눈 나머지를 출력한다.

입력

첫째 줄에 행렬의 크기 $N$ 과 $B$ 가 주어진다. $(2 \leq N \leq 5,\ 1 \leq B \leq 100,000,000,000)$

둘째 줄부터 $N$ 개의 줄에 행렬의 각 원소가 주어진다. 행렬의 각 원소는 $1,000$ 보다 작거나 같은 자연수 또는 $0$ 이다.

출력

첫째 줄부터 $N$ 개의 줄에 걸쳐 행렬 $A$ 를 $B$ 제곱한 결과를 출력한다.

풀이과정

1번째 시도

문제를 보고 분할 정복을 이용한 거듭제곱 문제임을 알 수 있었다. 단, 여기서는 행렬을 이용해야 했기 때문에 직접 Matrix 클래스를 구현하여 사용하였다.

코드는 다음과 같이 작성하였다.

#include <bits/stdc++.h>

template <typename T>
class Matrix {
public:
	size_t row;
	size_t column;

	T** elements;
public:
	Matrix(size_t row, size_t column) : row(row), column(column) {
		elements = new T * [row];

		for (size_t i = 0; i < row; i++) {
			elements[i] = new T[column]{};
		}
	}

	Matrix(size_t size, bool isIdentity = false) : row(size), column(size) {
		elements = new T * [size];
		for (size_t i = 0; i < size; i++) {
			elements[i] = new T[size]{};

			if (isIdentity == true) {
				elements[i][i] = static_cast<T>(1);
			}
		}
	}

	Matrix(const Matrix& other) : row(other.row), column(other.column) {
		elements = new T * [row];

		for (size_t i = 0; i < row; i++) {
			elements[i] = new T[column];

			for (size_t j = 0; j < column; j++) {
				elements[i][j] = other.elements[i][j];
			}
		}
	}

	~Matrix() {
		for (size_t i = 0; i < row; i++) {
			delete[] elements[i];
		}
		delete[] elements;
	}

	T* operator[] (size_t idx) {
		return elements[idx];
	}

	Matrix& operator= (const Matrix& other) {
		if (this == &other) {
			return *this;
		}

		for (size_t i = 0; i < row; i++) {
			delete[] elements[i];
		}
		delete[] elements;

		row = other.row;
		column = other.column;

		elements = new T * [row];
		for (size_t i = 0; i < row; i++) {
			elements[i] = new T[column];

			for (size_t j = 0; j < column; j++) {
				elements[i][j] = other.elements[i][j];
			}
		}

		return *this;
	}

	Matrix operator* (const Matrix& other) {
		Matrix result(this->row, other.column);

		for (size_t i = 0; i < result.row; i++) {
			for (size_t j = 0; j < result.column; j++) {
				result.elements[i][j] = 0;

				for (size_t k = 0; k < this->column; k++) {
					result.elements[i][j] += (this->elements[i][k] * other.elements[k][j] % static_cast<T>(1000));
					result.elements[i][j] %= static_cast<T>(1000);
				}
			}
		}

		return result;
	}

	Matrix power(size_t exponent) {
		Matrix base(*this);
		Matrix result(row, true);

		while (exponent > 0) {
			if (exponent % 2 == 1) {
				result = result * base;
			}
			exponent = exponent / 2;
			base = base * base;
		}

		return result;
	}
};

using namespace std;

int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    long long A, B;
    cin >> A >> B;

    Matrix<long long> mat(A);

    for (long long i = 0; i < A; i++) {
        for (long long j = 0; j < A; j++) {
            cin >> mat[i][j];
        }
    }

    Matrix<long long> result(mat.power(B));

    for (size_t i = 0; i < mat.row; i++) {
        for (size_t j = 0; j < mat.column; j++) {
            cout << result.elements[i][j] << " ";
        }
        cout << "\n";
    }

    return 0;
}

그러자 모든 테스트 케이스를 통과하고 정답이 나오는 것을 확인할 수 있었다.

마무리

PS를 하다보면 이런 식으로 직접 자료구조나 클래스를 구현하는 문제들이 뭔가 재밌다고 느껴진다. 객체 수업과 데이터구조 시간에 배운 내용을 써먹는다는 느낌이어서 그런 것일까?

그치만 매일 이런 문제가 나오면 너무 힘들 것 같다. 한 달에 한두 개 정도만 나오면 딱 적당할 것 같다.

오늘 만들어둔 Matrix 클래스는 살짝 수정하여 내 레포지토리2에 저장해두었으니 필요한 사람은 참고하길 바란다.

오늘의 PS는 여기까지!


1: https://www.acmicpc.net/problem/10830
2: https://github.com/ChoiCube84/baekjoon-solutions/blob/main/C%2B%2B/custom_data_structures/matrix.hpp